<?php

/**
 * 天猫淘宝cookie采集
 */

namespace console\controllers;

use Yii;
use yii\console\Controller;
use console\models\ComCookies;
use yii\helpers\FileHelper;

class TmallCookieController extends Controller
{
    /**
     * 登录跳转地址
     * @var string
     */
    protected $jump_url = 'https://login.taobao.com/jump';

    /**
     * cookie获取地址
     * @var string
     */
    protected $add_url = 'https://pass.tmall.com/add';

    /**
     * @var string
     */
    protected $referer = 'https://www.taobao.com/';


    public function actionSpider()
    {
        for ($i = 0; $i < 100; $i++) {
            echo $i . ":start" . PHP_EOL;
            list($jump_cookie, $query) = $this->getDataFromJumpUrl();
            $cookie = $this->getDataFromAddUrl($jump_cookie, $query);
            echo $i . ":end:" . $cookie . PHP_EOL;
            $this->saveData($cookie);
        }
        exit('end');
    }

    /**
     * @param $cookie
     * @throws \yii\base\Exception
     */
    protected function saveData($cookie)
    {
        $model = new ComCookies();
        $model->cookies = $cookie;
        $model->nums = 0;
        if (!$model->save()) {
            echo $model->errorsToString();
            $this->_writeLog($model->errorsToString());
            exit;
        }
    }

    /**
     * 从add url中获取cookie
     * @param $jump_cookie
     * @param $query
     * @return string
     * @throws \yii\base\Exception
     */
    protected function getDataFromAddUrl($jump_cookie, $query)
    {
        $add_url = $this->add_url . '?' . $query;
        $add_cookie = $jump_cookie['XSRF-TOKEN'] ?? '';
        if (!$add_cookie) {
            echo "XSRF-TOKEN error!";
            $this->_writeLog("XSRF-TOKEN error!");
            exit;
        }
        $header = [
            'cookie:' . $add_cookie,
            'referer: ' . $this->referer,
        ];
        $cookie_head = $this->curl_head($add_url, $header);
        $cookie_head_arr = $this->formatHead($cookie_head);
        $setCookies = $cookie_head_arr['Set-Cookie'] ?? [];
        if (!$setCookies) {
            echo "get add url cookie error!";
            $this->_writeLog("get add url cookie error!");
            exit;
        }
        return implode(";", $setCookies);
    }

    /**
     * 从login jump url中获取cookie and add url参数
     * @return array
     * @throws \yii\base\Exception
     */
    protected function getDataFromJumpUrl()
    {
        $item_url = $this->getItemUrl();
        $login_jump_url = $this->jump_url . "?target=" . urlencode($item_url . "&tbpm=1");
        $jump_head = $this->curl_head($login_jump_url);
        $jump_head_data = $this->formatHead($jump_head);
        $jump_cookie = $this->getCookie($jump_head_data);
        $location = $jump_head_data['Location'][0] ?? '';
        if (!$jump_cookie || !$location) {
            echo "jump url cookie get fail!";
            $this->_writeLog("jump url cookie get fail!");
            exit;
        }
        $location = 'https:' . $location;
        $url_data = parse_url($location);

        if (!isset($url_data['query']) || !$url_data['query']) {
            echo "location url error!";
            $this->_writeLog("location url error!");
            exit;
        }
        return [$jump_cookie, $url_data['query']];
    }

    /**
     * get cookie from array head data
     * @param $head
     * @return array
     */
    protected function getCookie($head)
    {
        $return = [];
        $setCookies = $head['Set-Cookie'] ?? [];
        foreach ($setCookies as $setCookie) {
            $arr = explode(";", $setCookie);
            foreach ($arr as $_arr) {
                $cookie_arr = explode("=", $_arr);
                $name = $cookie_arr[0] ?? '';
                $value = $cookie_arr[1] ?? '';
                if ($name && $value) {
                    $return[$name] = $_arr;
                }
            }
        }
        return $return;
    }

    /**
     * head string to arr
     * @param $headStr
     * @return array
     */
    protected function formatHead($headStr)
    {
        $return = [];
        $headArr = explode("\n", $headStr);
        foreach ($headArr as $_head) {
            $arr = explode(":", $_head);
            $name = $arr[0] ?? '';
            $value = $arr[1] ?? '';
            $value2 = $arr[2] ?? '';
            $name = trim($name);
            $value = trim($value);
            if ($name && $value) {
                $_value = $value;
                if ($value2) {
                    $_value .= ":" . $value2;
                }
                $return[$name] = $return[$name] ?? [];
                $return[$name][] = $_value;
            }
        }
        return $return;
    }


    /**
     * curl data
     * @param $sUrl
     * @param array $headers
     * @return array|false|string
     */
    protected function curl_head($sUrl, $headers = [])
    {
        $oCurl = curl_init();
        // 设置请求头, 有时候需要,有时候不用,看请求网址是否有对应的要求
        $header = $headers ? $headers : ["Content-type: application/x-www-form-urlencoded"];
        $user_agent = $this->getUserAgent();

        curl_setopt($oCurl, CURLOPT_URL, $sUrl);

        curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false); // 跳过证书验证（https）的网站无法跳过，会报错
        curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书验证

        curl_setopt($oCurl, CURLOPT_HTTPHEADER, $header);
        // 返回 response_header, 该选项非常重要,如果不为 true, 只会获得响应的正文
        curl_setopt($oCurl, CURLOPT_HEADER, true);
        // 是否不需要响应的正文,为了节省带宽及时间,在只需要响应头的情况下可以不要正文
        curl_setopt($oCurl, CURLOPT_NOBODY, true);
        // 使用上面定义的 ua
        curl_setopt($oCurl, CURLOPT_USERAGENT, $user_agent);
        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
        // 不用 POST 方式请求, 意思就是通过 GET 请求
        curl_setopt($oCurl, CURLOPT_POST, false);


        $sContent = curl_exec($oCurl);
        $error = curl_error($oCurl);
        // 获得响应结果里的：头大小
        $headerSize = curl_getinfo($oCurl, CURLINFO_HEADER_SIZE);

        // 根据头大小去获取头信息内容
        $header = substr($sContent, 0, $headerSize);

        curl_close($oCurl);
        return $header;
    }

    /**
     * get rand user agent
     * @return mixed
     */
    protected function getUserAgent()
    {
        $agents = [
            'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36',
            'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
            'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0'
        ];
        $count = count($agents) - 1;
        $rand = rand(0, $count);
        return $agents[$rand];
    }

    /**
     * get rand tmall item detail url
     * @return string
     */
    protected function getItemUrl()
    {
        $item_ids = ['624809445515', '615148409716', '620195499445', '625372259935', '602537381835', '628781243378', '615148409716',
            '624809445515', '620195499445', '625035414276', '623313868608', '626776539938', '626673761893', '624469583360', '623000066189',
            '627105840723', '622267528667', '624381576339', '625159199308', '621827125033', '622421717930', '624727211363', '602437354445',
            '606493803593', '606439867773', '601290099666', '606141561884', '602857824129', '606205016023', '600169520353', '605867145401',
            '626612581487', '624445939394'];
        $count = count($item_ids) - 1;
        $rand = rand(0, $count);
        return 'https://detail.tmall.com/item.htm?id=' . $item_ids[$rand];
    }

    /**
     * 文件日志记录
     * @param $msg
     * @throws \yii\base\Exception
     */
    private function _writeLog($msg)
    {

        $path = Yii::getAlias('@runtime/spider_tmall_cookie/');

        //目录如果不存就先创建目录
        if (!is_dir($path)) {
            FileHelper::createDirectory($path);
        }

        $cp = fopen($path . 'sync-items-' . date('Ymd') . '.log', "a+");
        $txt = "【" . date('Y-m-d H:i:s', time()) . "】---" . $msg . "\r\n";
        fwrite($cp, $txt);
        fclose($cp);
    }
}